using System;
using agsXMPP;
using Mono.Unix;
using Gtk;
using System.Configuration;
using agsXMPP.protocol.iq.roster;
using agsXMPP.protocol.client;
using agsXMPP.protocol.iq.vcard;
using agsXMPP.protocol.x.vcard_update;
using Notifications;
using agsXMPP.protocol.iq.disco;
using System.Threading;

/// <summary>
/// TODO: Repondre aux demande DiscoInfo (onIQ)
/// </summary>


namespace uShareReal
{
	
	/// <summary>
	/// Objet représentant un contact
	/// </summary>
	public class TreeRow
	{
		
		public RosterItem Item
		{
			get; set;
		}
		
		public Presence Pres
		{
			get; set;
		}
		
		public Gdk.Pixbuf Avatar
		{
			get; set;
		}
		
		public Vcard VCard
		{
			get; set;
		}
		
		public DiscoInfo DInfo
		{
			get; set;
		}
		
		public override string ToString()
		{
			return (Item != null) ? Item.Jid.Bare : string.Empty;
		}
		
	}
	
	public enum WatermarkPosition
	{
		TopLeft,
		TopRight,
		BottomLeft,
		BottomRight
	}
	
	public partial class UserWindow : Gtk.Window
	{
		
		#region Image manipulations
		
		private Gdk.Pixbuf ImageResizer(Gdk.Pixbuf p, int width, int height)
		{
			try
			{
				if(p == null)
					p = Gdk.Pixbuf.LoadFromResource("penguin.jpg");
				
				int w = p.Width;
				int h = p.Height;
				
				double ratio = 1.0;
				if(w >= h)
				{
					ratio = h / w;
					w = width;
					h = (int)(w * ratio);
				}
				else
				{
					ratio = w / h;
					h = height;
					w = (int)(h * ratio);
				}
				
				if(w < 1 || h < 1)
					return Gdk.Pixbuf.LoadFromResource("penguin.jpg").ScaleSimple(width, height, Gdk.InterpType.Bilinear);	
				
				return p.ScaleSimple(w, h, Gdk.InterpType.Bilinear);	
			}
			catch
			{
				return Gdk.Pixbuf.LoadFromResource("penguin.jpg").ScaleSimple(width, height, Gdk.InterpType.Bilinear);	
			}
		}
		
		private Gdk.Pixbuf ImageToPixbuf(System.Drawing.Image image)
		{
			using (System.IO.MemoryStream stream = new System.IO.MemoryStream()) {
				image.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
				stream.Position = 0;
				Gdk.Pixbuf pixbuf = new Gdk.Pixbuf(stream);
				return pixbuf;
			}
		}
		
		private System.Drawing.Bitmap PixbufToBitmap(Gdk.Pixbuf pixbuf)
		{
			if(pixbuf == null)
				return null;
			
			byte[] b = pixbuf.SaveToBuffer("png");
			if(b == null)
				return null;
			
			System.IO.MemoryStream ms = new System.IO.MemoryStream(b);
			return new System.Drawing.Bitmap(ms);
		}
		
		private Gdk.Pixbuf PixbufToGrayscalePixbuf(Gdk.Pixbuf pixbuf)
		{
			System.Drawing.Bitmap original = PixbufToBitmap(pixbuf);
			System.Drawing.Bitmap newbitmap = new System.Drawing.Bitmap(original.Width, original.Height);
			
			if(original == null)
				return pixbuf;
			
			System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(newbitmap);
			System.Drawing.Imaging.ColorMatrix colorMatrix = new System.Drawing.Imaging.ColorMatrix(
		      new float[][]
		      {
		         new float[] {.3f, .3f, .3f, 0, 0},
		         new float[] {.59f, .59f, .59f, 0, 0},
		         new float[] {.11f, .11f, .11f, 0, 0},
		         new float[] {0, 0, 0, 1, 0},
		         new float[] {0, 0, 0, 0, 1}
		      });
		   	System.Drawing.Imaging.ImageAttributes attributes = new System.Drawing.Imaging.ImageAttributes();
		   	attributes.SetColorMatrix(colorMatrix);
		   	g.DrawImage(original, new System.Drawing.Rectangle(0, 0, original.Width, original.Height), 0, 0, original.Width, original.Height, System.Drawing.GraphicsUnit.Pixel, attributes);
		   	g.Dispose();
			return ImageToPixbuf(newbitmap);
		}
		
		private Gdk.Pixbuf WatermarkPixbuf(Gdk.Pixbuf pixbuf, Gdk.Pixbuf watermark, WatermarkPosition position)
		{
			if(pixbuf == null || watermark == null)
				return pixbuf;
			
			double sw = pixbuf.Width;
			double sh = pixbuf.Height;
			double ss = (sw >= sh) ? sh : sw;
			double ws = Math.Ceiling(ss / 2);
			if(ws < 1)
				ws = 1;
			
			watermark = watermark.ScaleSimple((int)ws, (int)ws, Gdk.InterpType.Bilinear);
			
			System.Drawing.Bitmap b = PixbufToBitmap(pixbuf);
			System.Drawing.Bitmap w = PixbufToBitmap(watermark);
			
			if(b == null || w == null)
				return pixbuf;
			
			System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(b);
			
			int x = 0;
			int y = 0;
			switch(position)
			{
			case WatermarkPosition.BottomLeft:
				x = 0;
				y = b.Height - w.Height;
				break;
			case WatermarkPosition.BottomRight:
				x = b.Width - w.Width;
				y = b.Height - w.Height;
				break;
			case WatermarkPosition.TopLeft:
				x = 0;
				y = 0;
				break;
			case WatermarkPosition.TopRight:
				x = b.Width - w.Width;
				y = 0;
				break;
			}
			
			g.DrawImage(w, new System.Drawing.Rectangle(x, y, w.Width, w.Height));
			
			return ImageToPixbuf(b);
		}
		
		private string GdkColorToRgbString(Gdk.Color color)
		{
			return String.Format("#{0:X2}{1:X2}{2:X2}", (int)Math.Truncate(color.Red / 256.00), (int)Math.Truncate(color.Green / 256.00), (int)Math.Truncate(color.Blue / 256.00)).Replace(".", "").Replace(",", "");
		}
		
		#endregion

		#region Timers functions
		
		bool update_status ()
		{
			TimeSpan delay = DateTime.Now.Subtract(MainWindow.connectedTime);

			string t = string.Format(Catalog.GetString("Connecté sur <span font_weight='bold'>{0}</span> via <span font_weight='bold'>{1}</span> depuis"), Xmpp.MyJID.Server, Xmpp.MyJID.User);
			
			if(delay.Days > 0)
				t += " " + delay.Days + " " + Catalog.GetString("jours");

			if(delay.Hours > 0)
				t += " " + delay.Hours + " " + Catalog.GetString("heures");
			
			if(delay.Minutes > 0)
				t += " " + delay.Minutes + " " + Catalog.GetString("minutes");
				
			if(delay.Minutes == 0 && delay.Hours == 0 && delay.Days == 0)
				t += " " + Catalog.GetString("moins d'une minute");

			if(label1.Text != ("<small>" + t + "</small>"))
				label1.LabelProp = "<small>" + t + "</small>";
			
			return true;
		}
		
		bool refresh_contact()
		{
			TreeFilter.Refilter();
			treeview3.QueueDraw();

			state_Changed(null, null);
			
			return false;
		}
		
		#endregion
		
		#region Private functions
		
		private bool AcceptSubscription(Jid from)
		{
			if(MainClass.Config.AutoAcceptSubscribtion)
				return true;
			
			if(MainClass.Config.AutoRefuseSubscribtion)
				return false;
			
			bool response = false;
			
			ManualResetEvent ev = new ManualResetEvent(false);
			
			Gtk.Application.Invoke(delegate {
				SusUnsus su = new SusUnsus(from);
				response = ((ResponseType)su.Run() == ResponseType.Yes);
				su.Destroy();
				ev.Set();
			});
			
			ev.WaitOne();
			
			while (Gtk.Application.EventsPending ())
              		Gtk.Application.RunIteration ();
			
			return response;
		}
		
		#endregion
		
		#region Xmpp Events

		private void XmppRosterStart(object sender)
		{
			TreeRoster = new TreeStore(typeof(Gdk.Pixbuf), typeof(Gdk.Pixbuf), typeof(TreeRow));
		}
		
		private void XmppRosterItem(object sender, RosterItem item)
		{
			Gtk.Application.Invoke(delegate {
				bool ok = false;
				TreeRoster.Foreach(delegate (TreeModel model, TreePath path, TreeIter iter) {
					if(!TreeRoster.IterIsValid(iter))
						return false;
					
			    	TreeRow row = (TreeRow)model.GetValue (iter, 2);
					if(row.Item != null && row.Item.Jid.Bare == item.Jid.Bare)
					{
						ok = true;
						return true;
					}
					return false;
				}); 
	
				if(!ok)
				{
					TreeRow row = new TreeRow();
					row.Item = item;
					row.Pres = new Presence(ShowType.NONE, string.Empty);
					row.Pres.Type = PresenceType.unavailable;
					row.Pres.Nickname = new agsXMPP.protocol.extensions.nickname.Nickname(item.Jid.Bare);
					row.Avatar = null;
					row.VCard = new Vcard();
					row.DInfo = new DiscoInfo();
					TreeRoster.AppendValues(Gdk.Pixbuf.LoadFromResource("offline.png"), ImageResizer(Gdk.Pixbuf.LoadFromResource("penguin.jpg"), 32, 32), row);
				}
				else if(item.Subscription == SubscriptionType.remove)
				{
					TreeRoster.Foreach(delegate (TreeModel model, TreePath path, TreeIter iter) {
				    	TreeRow row = (TreeRow)model.GetValue (iter, 2);
						if(row.Item != null && row.Item.Jid.Bare == item.Jid.Bare)
						{
							TreeRoster.Remove(ref iter);
							return true;
						}
						return false;
					});
				}
				
				while (Gtk.Application.EventsPending ())
              		Gtk.Application.RunIteration ();
				
			});
		}
		
		private void XmppRosterEnd(object sender)
		{
			Gtk.Application.Invoke(delegate {
				TreeFilter = new TreeModelFilter(TreeRoster, null);
				TreeSort = new TreeModelSort(TreeFilter);
				TreeSort.SetSortFunc(2, TreeSortFunc);
				TreeFilter.VisibleFunc = new TreeModelFilterVisibleFunc(TreeFilterFunc);
				treeview3.Model = TreeSort;
				TreeColumnPhoto.SetCellDataFunc(ct0, new Gtk.TreeCellDataFunc(TreeRenderIcon));
				TreeColumnAvatar.SetCellDataFunc(ct2, new Gtk.TreeCellDataFunc(TreeRenderAvatar));
				TreeColumnItem.SetCellDataFunc(ct1, new Gtk.TreeCellDataFunc(TreeRenderItem));
				
				while (Gtk.Application.EventsPending ())
              		Gtk.Application.RunIteration ();

				TreeSort.SetSortColumnId(2, SortType.Ascending);
				
				treeview3.QueueDraw();
				
				GLib.Timeout.Add (500, new GLib.TimeoutHandler (refresh_contact));
				
			});
		}
		
		private void XmppPresence(object sender, Presence pres)
		{
			SubscriptionType st = SubscriptionType.none;
			if(pres.Type == PresenceType.subscribe)
			{
				if(AcceptSubscription(pres.From))
				{
					Xmpp.PresenceManager.ApproveSubscriptionRequest(pres.From);
					st = SubscriptionType.both;
				}
				else
				{
					Xmpp.PresenceManager.RefuseSubscriptionRequest(pres.From);
					st = SubscriptionType.remove;
				}
				
			}

			TreeRoster.Foreach(delegate (TreeModel model, TreePath path, TreeIter iter) {
				if(!TreeRoster.IterIsValid(iter))
					return false;
				
			    TreeRow row = (TreeRow)model.GetValue (iter, 2);
				if(row != null && row.Item != null && row.Item.Jid.Bare.Trim().ToLower() == pres.From.Bare.Trim().ToLower())
				{
					Gdk.Pixbuf av = row.Avatar;
					if(av == null)
						av = Gdk.Pixbuf.LoadFromResource("penguin.jpg");
					
					av = ImageResizer(av, 32, 32);
					
					string nk = ((row.Item.Name != null) ? row.Item.Name : (pres.Nickname != null && !string.IsNullOrEmpty(pres.Nickname.Value) ? pres.Nickname.Value.Trim() : row.Item.Jid.Bare));
					if(!string.IsNullOrEmpty(row.VCard.Nickname) && row.VCard.Nickname.Trim() != string.Empty)
						nk = row.VCard.Nickname;
					
					MainClass.TrayNotification.Urgency = Urgency.Low;
					
					if(row.Pres.Type != PresenceType.available && pres.Type == PresenceType.available)
					{
						MainClass.TrayNotification.Icon = av;
						MainClass.TrayNotification.Body = "<b>" + Catalog.GetString("Connexion de ") + nk + "</b>\r\n" + pres.From.Bare;
						if(MainClass.Config.ShowNotifyBaloons && MainClass.Config.ShowNotifyOnContactConnectDisconnect)
							MainClass.TrayNotification.Show();
						
					} else if(row.Pres.Type == PresenceType.available && pres.Type != PresenceType.available)
					{
						MainClass.TrayNotification.Icon = PixbufToGrayscalePixbuf(av);
						MainClass.TrayNotification.Body = "<b>" + Catalog.GetString("Déconnexion de ") + nk + "</b>\r\n" + pres.From.Bare;
						if(MainClass.Config.ShowNotifyBaloons && MainClass.Config.ShowNotifyOnContactConnectDisconnect)
							MainClass.TrayNotification.Show();
						
					} else if(pres.Type == PresenceType.available && row.Pres.Show != ShowType.away && pres.Show == ShowType.away)
					{
						MainClass.TrayNotification.Icon = av;
						MainClass.TrayNotification.Body = "<b>" + nk + Catalog.GetString(" indique qu'il s'absente.") + "</b>\r\n" + pres.From.Bare;
						if(MainClass.Config.ShowNotifyBaloons && MainClass.Config.ShowNotifyOnContactStateChange)
							MainClass.TrayNotification.Show();
						
					} else if(pres.Type == PresenceType.available && row.Pres.Show != ShowType.dnd && pres.Show == ShowType.dnd)
					{
						MainClass.TrayNotification.Icon = av;
						MainClass.TrayNotification.Body = "<b>" + nk + Catalog.GetString(" indique de ne pas le déranger.") + "</b>\r\n" + pres.From.Bare;
						if(MainClass.Config.ShowNotifyBaloons && MainClass.Config.ShowNotifyOnContactStateChange)
							MainClass.TrayNotification.Show();
						
					} else if(pres.Type == PresenceType.available && row.Pres.Show != ShowType.xa && pres.Show == ShowType.xa)
					{
						MainClass.TrayNotification.Icon = av;
						MainClass.TrayNotification.Body = "<b>" + nk + Catalog.GetString(" indique qu'il est occupé.") + "</b>\r\n" + pres.From.Bare;
						if(MainClass.Config.ShowNotifyBaloons && MainClass.Config.ShowNotifyOnContactStateChange)
							MainClass.TrayNotification.Show();
						
					} else if(pres.Type == PresenceType.available && row.Pres.Show != ShowType.NONE && pres.Show == ShowType.NONE)
					{
						MainClass.TrayNotification.Icon = av;
						MainClass.TrayNotification.Body = "<b>" + nk + Catalog.GetString(" indique qu'il est disponible.") + "</b>\r\n" + pres.From.Bare;
						if(MainClass.Config.ShowNotifyBaloons && MainClass.Config.ShowNotifyOnContactStateChange)
							MainClass.TrayNotification.Show();
						
					}
					
					if(pres.Type == PresenceType.available)
					{
						VcardIq viq = new VcardIq(IqType.get, new Jid(pres.From.Bare));
						Xmpp.IqGrabber.SendIq(viq, new IqCB(VcardResult), null);
						
						if(row.Pres.Type != PresenceType.available)
						{
							DiscoManager dm = new DiscoManager(Xmpp);
							dm.DiscoverInformation(pres.From, new IqCB(DiscoServerResult), null);
						}
					}
					
					row.Pres = pres;
					
					if(st != SubscriptionType.none)
						row.Item.Subscription = st;
	
					TreeRoster.EmitRowChanged(path, iter);
					TreeFilter.EmitRowChanged(path, iter);
					TreeFilter.Refilter();
					treeview3.QueueDraw();

					return true;
				}
				return false;
			});
		}
		
		#endregion
		
		#region Contact tree renderers, filter and sorter
		
		private bool TreeFilterFunc(TreeModel model, TreeIter iter)
		{
			if(MainClass.Config.ShowContactDisconnected)
				return true;
			
			object v = model.GetValue(iter, 2);
			if(v != null)
			{
				TreeRow row = v as TreeRow;
				if(row != null && row.Item != null && row.Pres != null)
				{
					if(row.Pres.Type != PresenceType.available)
						return false;
					
				}	
			}
			
			return true;
		}
		
		private int TreeSortFunc(TreeModel model, TreeIter tia, TreeIter tib)
		{
			object o1 = model.GetValue (tia, 2);
			object o2 = model.GetValue (tib, 2);
			if(o1 == null || o2 == null)
				return 0;
				
			try
			{
				TreeRow row1 = o1 as TreeRow;
				TreeRow row2 = o2 as TreeRow;
				if(row1 != null && row1.Item != null && row1.Pres != null && row2 != null && row2.Item != null && row2.Pres != null)
				{
					string ai1 = ((row1.Item.Name != null) ? row1.Item.Name : (row1.Pres.Nickname != null && !string.IsNullOrEmpty(row1.Pres.Nickname.Value) ? row1.Pres.Nickname.Value.Trim() : row1.Item.Jid.Bare));
					string ai2 = ((row2.Item.Name != null) ? row2.Item.Name : (row2.Pres.Nickname != null && !string.IsNullOrEmpty(row1.Pres.Nickname.Value) ? row2.Pres.Nickname.Value.Trim() : row2.Item.Jid.Bare));
					if(string.IsNullOrEmpty(ai1) || string.IsNullOrEmpty(ai2))
						return 0;
					
					return string.Compare(ai1, ai2);
				}
			}
			catch { }
			
			return 0;
		}
		
		private void TreeRenderIcon(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
		{
			TreeRow row = (TreeRow)model.GetValue (iter, 2);
			if(row == null)
				return; 
			
			CellRendererPixbuf c = cell as CellRendererPixbuf;
			if(row.Pres.Type != PresenceType.available)
			{
				switch(row.Pres.Type)
				{
				case PresenceType.invisible:
					c.Pixbuf = Gdk.Pixbuf.LoadFromResource("invisible.png");
					break;
				default:
					c.Pixbuf = Gdk.Pixbuf.LoadFromResource("offline.png");
					break;
				}
			}
			if(row.Pres.Type == PresenceType.available)
			{
				switch(row.Pres.Show)
				{
				case ShowType.away:
					c.Pixbuf = Gdk.Pixbuf.LoadFromResource("away.png");
					break;
				case ShowType.chat:
					c.Pixbuf = Gdk.Pixbuf.LoadFromResource("chat.png");
					break;
				case ShowType.dnd:
					c.Pixbuf = Gdk.Pixbuf.LoadFromResource("busy.png");
					break;
				case ShowType.NONE:
					c.Pixbuf = Gdk.Pixbuf.LoadFromResource("available.png");
					break;
				case ShowType.xa:
					c.Pixbuf = Gdk.Pixbuf.LoadFromResource("extended-away.png");;
					break;
				}
			}
			
			c.Yalign = 0.5f;
			c.Width = MainClass.Config.ShowContactAvatarSmallSize;
		}
		
		private void TreeRenderAvatar(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
		{
			TreeRow row = (TreeRow)model.GetValue (iter, 2);
			if(row == null)
				return; 
			
			CellRendererPixbuf c = cell as CellRendererPixbuf;
			
			int pw = 32;
			int ph = 32;
			if(MainClass.Config.ShowContactSimpleList)
			{
				pw = 16;
				ph = 16;
			}
			
			if(!c.Pixbuf.Equals(row.Avatar) || (c.Pixbuf != null && (c.Pixbuf.Width != pw || c.Pixbuf.Height != ph)))
				c.Pixbuf = ImageResizer((row.Avatar != null ? row.Avatar : Gdk.Pixbuf.LoadFromResource("penguin.jpg")), pw, ph);
			
			if(row.Pres.Type != PresenceType.available)
				c.Pixbuf = PixbufToGrayscalePixbuf(c.Pixbuf);
			else
			{
				if(row.DInfo.HasFeature("http://uShareReal.com/sharing"))
					c.Pixbuf = WatermarkPixbuf(c.Pixbuf, Gdk.Pixbuf.LoadFromResource("emblemusr.png"), WatermarkPosition.BottomRight);
				
			}
			
			if(row.Item.Subscription == SubscriptionType.none
			   || row.Item.Subscription == SubscriptionType.remove
			   || row.Item.Subscription == SubscriptionType.to)
				c.Pixbuf = WatermarkPixbuf(c.Pixbuf, Gdk.Pixbuf.LoadFromResource("unsuscribed.png"), WatermarkPosition.TopLeft);
			
			c.Yalign = 0.5f;
			c.Xalign = 0.5f;
		}
		
		private void TreeRenderItem(Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
		{
			TreeRow row = (TreeRow)model.GetValue (iter, 2);
			if(row == null)
				return;
			
			Gtk.CellRendererText c = cell as Gtk.CellRendererText;
			
			RosterItem item = row.Item;
			if(item != null)
			{
				string state = string.Empty;
				switch(row.Pres.Type)
				{
				case PresenceType.error:
					state = Catalog.GetString("Erreur");
					break;
				case PresenceType.invisible:
					state = Catalog.GetString("Invisible");
					break;
				default:
					state = Catalog.GetString("Indisponible");
					break;
				}
				if(row.Pres.Type == PresenceType.available)
				{
					switch(row.Pres.Show)
					{
					case ShowType.away:
						state = Catalog.GetString("Absent");
						break;
					case ShowType.chat:
						state = Catalog.GetString("En discussion");
						break;
					case ShowType.dnd:
						state = Catalog.GetString("Ne pas déranger");
						break;
					case ShowType.NONE:
						state = Catalog.GetString("Disponible");
						break;
					case ShowType.xa:
						state = Catalog.GetString("Occupé");
						break;
					}
				}

				string colorHTML = GdkColorToRgbString(treeview3.Style.Foreground(StateType.Normal));
				string colorHTMLDisabled = GdkColorToRgbString(treeview3.Style.Foreground(StateType.Insensitive));
				string colorHTMLSelected = GdkColorToRgbString(treeview3.Style.Foreground(StateType.Selected));
				
				TreeIter selIter;
				if(treeview3.Selection.GetSelected(out selIter))
				{
					if(selIter.Equals(iter))
					{
						colorHTML = colorHTMLSelected;
						colorHTMLDisabled = colorHTMLSelected;
					}
				}
				
				string rs = string.Empty;
				rs = "<span foreground='" + (row.Pres.Type == PresenceType.available ? colorHTML : colorHTMLDisabled) + "'>";
				
				string nk = ((item.Name != null) ? item.Name : (row.Pres.Nickname != null && !string.IsNullOrEmpty(row.Pres.Nickname.Value) ? row.Pres.Nickname.Value.Trim() : item.Jid.Bare));
				if(!string.IsNullOrEmpty(row.VCard.Nickname) && row.VCard.Nickname.Trim() != string.Empty)
					nk = row.VCard.Nickname;
				
				rs += nk;
				rs += "</span>";
				if(!MainClass.Config.ShowContactSimpleList)
				{
					if(MainClass.Config.ShowContactAddress)
					{
						rs += "\r\n<span foreground='" + (row.Pres.Type == PresenceType.available ? colorHTML : colorHTMLDisabled) + "'><small>";
						rs += item.Jid.Bare;
						rs += "</small></span>";
					}
					rs += "\r\n<span foreground='" + (row.Pres.Type == PresenceType.available ? colorHTML : colorHTMLDisabled) + "'><small>";
					rs += state + (!string.IsNullOrEmpty(row.Pres.Status) ? " - " + row.Pres.Status.Trim() : string.Empty);
					rs += "</small></span>";
				}

				c.Markup = rs;
			}
		}
		
		#endregion
		
		#region IQ Results
		
		private void VcardResult(object sender, IQ iq, object data)
    	{
			if(iq.Type == IqType.result)
      		{
				Vcard vcard = iq.Vcard;
				if(vcard != null)
				{
					TreeRoster.Foreach(delegate (TreeModel model, TreePath path, TreeIter iter) {
						if(!TreeRoster.IterIsValid(iter))
							return false;
						
					    TreeRow row = (TreeRow)model.GetValue (iter, 2);
						if(row != null && row.Item != null && row.Item.Jid.Bare.Trim().ToLower() == iq.From.Bare.Trim().ToLower())
						{
							row.VCard = vcard;
							if(row.Avatar == null && vcard.Photo != null && vcard.Photo.Image.Width > 1 && vcard.Photo.Image.Height > 1)
								row.Avatar = ImageToPixbuf(vcard.Photo.Image);
			
							TreeRoster.EmitRowChanged(path, iter);
							TreeFilter.EmitRowChanged(path, iter);
							TreeFilter.Refilter();
							treeview3.QueueDraw();
		
							return true;
						}
						return false;
					});
				}
			}
		}
		
		private void DiscoServerResult(object sender, IQ iq, object data)
		{
			if(iq.Type == IqType.result)
			{
				agsXMPP.Xml.Dom.Element query = iq.Query;
				if(query != null)
				{
					Type qT = query.GetType();
	                if(qT == typeof(DiscoItems))
	                {
						DiscoItems items = query as DiscoItems;
	                    DiscoItem[] itms = items.GetDiscoItems();
	                    DiscoManager dm = new DiscoManager(Xmpp);
	                    foreach (DiscoItem itm in itms)
	                    {
	                        if (itm.Jid != null)
	                            dm.DiscoverInformation(itm.Jid, new IqCB(DiscoInfoResult), itm);
							
	                    }
					}
					else if(qT == typeof(DiscoInfo))
						DiscoInfoResult(sender, iq, data);
					
				}
			}
		}
		
		private void DiscoInfoResult(object sender, IQ iq, object data)
        {
            if(iq.Type == IqType.result)
            {
                if(iq.Query is DiscoInfo)
                {
                    DiscoInfo di = iq.Query as DiscoInfo;

					TreeRoster.Foreach(delegate (TreeModel model, TreePath path, TreeIter iter) {
						if(!TreeRoster.IterIsValid(iter))
							return false;
						
					    TreeRow row = (TreeRow)model.GetValue (iter, 2);
						if(row != null && row.Item != null && row.Item.Jid.Bare.Trim().ToLower() == iq.From.Bare.Trim().ToLower())
						{
							row.DInfo = di;
			
							TreeRoster.EmitRowChanged(path, iter);
							TreeFilter.EmitRowChanged(path, iter);
							TreeFilter.Refilter();
							treeview3.QueueDraw();
		
							return true;
						}
						return false;
					});
					
				}
			}
		}
		
		#endregion
		
		private XmppClientConnection Xmpp = null;
		private uShareReal.Objects.Account Account = null;
		private TreeViewColumn TreeColumnPhoto = null;
		private TreeViewColumn TreeColumnAvatar = null;
		private TreeViewColumn TreeColumnItem = null;
		private TreeStore TreeRoster = null;
		private CellRendererPixbuf ct0;
		private CellRendererText ct1;
		private CellRendererPixbuf ct2;
		private TreeModelFilter TreeFilter;
		private TreeModelSort TreeSort;
		private SeparatorMenuItem menuItemStateSeparator = null;
		private MenuItem menuItemState = null;
		private GLib.SList menuItemStateGroup = null;
		private RadioMenuItem menuItemStateAvailable = null;
		private RadioMenuItem menuItemStateAway = null;
		private RadioMenuItem menuItemStateDnd = null;
		
		public UserWindow (XmppClientConnection xmpp, uShareReal.Objects.Account account) : base(Gtk.WindowType.Toplevel)
		{
			this.Build ();
			
			Account = account;
			Xmpp = xmpp;

			GLib.Timeout.Add (500, new GLib.TimeoutHandler (update_status));
			
			Xmpp.OnRosterStart += new ObjectHandler(XmppRosterStart);
			Xmpp.OnRosterItem += new XmppClientConnection.RosterHandler(XmppRosterItem);
			Xmpp.OnRosterEnd += new ObjectHandler(XmppRosterEnd);
			xmpp.OnPresence += new PresenceHandler(XmppPresence);
			
			InitializeUI();
			
			RosterIq riq = new RosterIq(IqType.get);
			riq.From = Xmpp.MyJID;
			Xmpp.Send(riq);
			
		}
		
		private void InitializeUI()
		{
			treeview3.Selection.Changed += new EventHandler(TreeSelectionChanged);
			
			label1.LabelProp = "<small>" + string.Format(Catalog.GetString("Connecté sur <span font_weight='bold'>{0}</span> via <span font_weight='bold'>{1}</span> depuis moins d'une minute"), Xmpp.MyJID.Server, Xmpp.MyJID.User) + "</small>";
			combobox2.Active = Account.State;
			
			menuItemStateSeparator = new SeparatorMenuItem();
			MainClass.TrayPopupMenu.Prepend(menuItemStateSeparator);
			menuItemState = new MenuItem(Catalog.GetString("Mon status"));
			
			Menu m = new Menu();
			menuItemStateGroup = new GLib.SList(typeof(RadioMenuItem));
			menuItemStateAvailable = new RadioMenuItem(menuItemStateGroup, Catalog.GetString("Disponible"));
			menuItemStateAvailable.Active = false;
			menuItemStateAvailable.Activated += new EventHandler(TrayMenuStateActivated);
			menuItemStateGroup.Append(menuItemStateAvailable);
			m.Append(menuItemStateAvailable);
			menuItemStateAway = new RadioMenuItem(menuItemStateGroup, Catalog.GetString("Absent"));
			menuItemStateAway.Active = false;
			menuItemStateAway.Activated += new EventHandler(TrayMenuStateActivated);
			menuItemStateGroup.Append(menuItemStateAway);
			m.Append(menuItemStateAway);
			menuItemStateDnd = new RadioMenuItem(menuItemStateGroup, Catalog.GetString("Occupé"));
			menuItemStateDnd.Active = false;
			menuItemStateDnd.Activated += new EventHandler(TrayMenuStateActivated);
			menuItemStateGroup.Append(menuItemStateDnd);
			m.Append(menuItemStateDnd);
			
			menuItemState.Submenu = m;
			MainClass.TrayPopupMenu.Prepend(menuItemState);
			
			combobox2.Changed += new EventHandler(state_Changed);
			
			VoirLesContactsDconnectsAction.Active = MainClass.Config.ShowContactDisconnected;
			if(MainClass.Config.ShowContactSimpleList)
				ListeSimpleAction.Active = true;
			else
			{
				ListeSimpleAction.Active = false;
				if(MainClass.Config.ShowContactAddress)
					ListeTendueAction.Active = true;
				else
					ListeNormaleAction.Active = true;
				
			}
			
			ct0 = new CellRendererPixbuf();
			ct1 = new CellRendererText();
			ct2 = new CellRendererPixbuf();
			TreeColumnPhoto = new TreeViewColumn("s", ct0, "pixbuf", 0);
			TreeColumnPhoto.Sizing = TreeViewColumnSizing.Fixed;
			TreeColumnPhoto.FixedWidth = 40;
			TreeColumnItem = new TreeViewColumn("n", ct1, "text", 2);
			TreeColumnItem.MaxWidth = 500;
			TreeColumnAvatar = new TreeViewColumn("a", ct2, "pixbuf", 1);
			TreeColumnAvatar.Sizing = TreeViewColumnSizing.Fixed;
			TreeColumnAvatar.FixedWidth = 36;
			treeview3.AppendColumn(TreeColumnPhoto);
			treeview3.AppendColumn(TreeColumnAvatar);
			treeview3.AppendColumn(TreeColumnItem);
			
			treeview3.FixedHeightMode = true;
		}
		
		private void TrayMenuStateActivated(object sender, EventArgs e)
		{
			if(menuItemStateAvailable.Active)
				combobox2.Active = 0;
			else if(menuItemStateAway.Active)
				combobox2.Active = 1;
			else if(menuItemStateDnd.Active)
				combobox2.Active = 2;
			
		}
		
		protected virtual void state_Changed (object sender, System.EventArgs e)
		{
			Account.State = combobox2.Active;
			
			Xmpp.Status = Account.Status;
			
			if(combobox2.Active == 0)
			{
				Xmpp.Show = agsXMPP.protocol.client.ShowType.NONE;
				MainClass.TrayIcon.Pixbuf = Gdk.Pixbuf.LoadFromResource("icon.png");
				menuItemStateAvailable.Active = true;
			}

			if(combobox2.Active == 1)
			{
				Xmpp.Show = agsXMPP.protocol.client.ShowType.away;
				MainClass.TrayIcon.Pixbuf = Gdk.Pixbuf.LoadFromResource("iconAway.png");
				menuItemStateAway.Active = true;
			}

			if(combobox2.Active == 2)
			{
				Xmpp.Show = agsXMPP.protocol.client.ShowType.dnd;
				MainClass.TrayIcon.Pixbuf = Gdk.Pixbuf.LoadFromResource("iconDnd.png");
				menuItemStateDnd.Active = true;
			}

			Xmpp.SendMyPresence();
		}
		
		public void OnPublicDelete()
		{
			menuItemState.Destroy();
			menuItemStateSeparator.Destroy();
		}
		
		protected virtual void OnDelete (object o, Gtk.DeleteEventArgs args)
		{
			OnPublicDelete();
		}
		
		protected virtual void OnContactsDconnectsActionActivated (object sender, System.EventArgs e)
		{
			MainClass.Config.ShowContactDisconnected = VoirLesContactsDconnectsAction.Active;
			
			if(TreeFilter != null)
				TreeFilter.Refilter();
			
			treeview3.QueueDraw();			
		}
		
		protected virtual void OnListeSimpleActionActivated (object sender, System.EventArgs e)
		{
			MainClass.Config.ShowContactSimpleList = true;
			
			if(TreeFilter != null)
				TreeFilter.Refilter();
			
			treeview3.QueueDraw();
		}
		
		protected virtual void OnListeNormaleActionActivated (object sender, System.EventArgs e)
		{
			MainClass.Config.ShowContactSimpleList = false;
			MainClass.Config.ShowContactAddress = false;
			
			if(TreeFilter != null)
				TreeFilter.Refilter();
			
			treeview3.QueueDraw();
		}
		
		protected virtual void OnListeTendueActionActivated (object sender, System.EventArgs e)
		{
			
			MainClass.Config.ShowContactSimpleList = false;
			MainClass.Config.ShowContactAddress = true;
			
			if(TreeFilter != null)
				TreeFilter.Refilter();
			
			treeview3.QueueDraw();
		}
		
		protected virtual void OnHelpActionActivated (object sender, System.EventArgs e)
		{
			About ab = new About();
			ab.Run();
		}
		
		protected virtual void TreeSelectionChanged (object sender, System.EventArgs e)
		{
			removeAction.Sensitive = false;
			yesAction.Sensitive = false;
			noAction.Sensitive = false;
			
			if(sender == null || !(sender is Gtk.TreeSelection))
				return;
			
			Gtk.TreeSelection selection = sender as Gtk.TreeSelection;
			if(selection.Mode == SelectionMode.Single)
			{
				TreeModel model;
				TreeIter iter;
				if(selection.GetSelected(out model, out iter))
				{
					GLib.Value val = GLib.Value.Empty;
					model.GetValue(iter, 2, ref val);
					if(val.Val.GetType() == typeof(TreeRow))
					{
						TreeRow row = (TreeRow)val.Val;
						removeAction.Sensitive = true;
						if(row.Item.Subscription == SubscriptionType.to)
							yesAction.Sensitive = true;
						
						if(row.Item.Subscription == SubscriptionType.both)
							noAction.Sensitive = true;
						
					}
				}
			}
		}
		
		
		
		
		
		
		
		
		
		
		
		
		
		
	}
	
}